import time
from util import display, button, buttonDownLevel


# button event detect
class BtnEvtDet:
	def __init__(self, holdTime=500, idleTime=3000):
		# init state
		self.S_INIT = 0
		self.S_CLICK = 1
		self.S_HOLD = 2
		self.state = self.S_INIT

		# time stamp
		self.clickTs = 0
		self.initTs = time.ticks_ms()
		self.HOLD_TIME = holdTime
		self.IDLE_TIME = idleTime

	def detect(self):
		pinValue = button.value()  # read
		if self.state == self.S_INIT:  # init state
			if pinValue == buttonDownLevel:  # down
				self.state = self.S_CLICK
				self.clickTs = time.ticks_ms()
				return 0  # idle
			else:  # up
				if time.ticks_ms() - self.initTs >= self.IDLE_TIME:
					self.initTs = time.ticks_ms()
					return 5  # timeout
				else:
					return 0  # idle
		elif self.state == self.S_CLICK:  # click state
			if pinValue == buttonDownLevel:  # down
				# hold more than 300ms (default)
				if time.ticks_ms() - self.clickTs >= self.HOLD_TIME:
					self.state = self.S_HOLD
					return 2  # hold
			else:  # up
				self.state = self.S_INIT
				self.initTs = time.ticks_ms()
				return 1  # click
		elif self.state == self.S_HOLD:
			if pinValue == buttonDownLevel:  # down
				return 3  # holding
			else:  # up
				self.state = self.S_INIT
				self.initTs = time.ticks_ms()
				return 4  # release


class Window:
	def __init__(self, sampleTime=150):
		self.componets = []
		self.comp_num = 0
		self.focusIndex = -1
		self.quit = False
		self.bed = BtnEvtDet()
		self.SAMPLE_TIME = sampleTime
		self.timeStamp = time.ticks_ms()

		self._cb_draw = None
		self._cb_idle = None
		self._cb_timeout = None
		self._cb_click = None
		self._cb_hold = None
		self._cb_holding = None
		self._cb_release = None

		self._hold_with_param_flag = 1
		self.hold_title = -1

	def show(self):
		display.fill(0)
		if self._cb_draw != None:
			self._cb_draw()
		for c in self.componets:
			c.draw()
		display.show()

	# window callbacks
	def setDrawCB(self, draw):
		self._cb_draw = draw

	def setIdleCB(self, idle):
		self._cb_idle = idle

	def setTimeoutCB(self, timeout):
		self._cb_timeout = timeout

	def setClickCB(self, click):
		self._cb_click = click

	def setHoldCB(self, hold):
		self._cb_hold = hold

	def setHoldingCB(self, holding):
		self._cb_holding = holding

	def setReleaseCB(self, release):
		self._cb_release = release

	def add(self, c):
		self.componets.append(c)
		self.comp_num += 1

	# loop
	def run(self):
		self.quit = False
		while not self.quit:
			evt = self.bed.detect()
			self.handle(evt)
			self.show()
			dt = self.SAMPLE_TIME - (time.ticks_ms() - self.timeStamp)
			if dt > 0:
				time.sleep_ms(dt)
			self.timeStamp = time.ticks_ms()

	def close(self):
		self.quit = True

	# handle event
	def handle(self, evt):
		if evt == 0 and self._cb_idle != None:  #idle
			self._cb_idle()
		elif evt == 1:  # click
			self._click()
		elif evt == 2:  # hold
			if (self._hold_with_param_flag == 1):
				self._hold_with_param()
			else:
				self._hold()
		elif evt == 3:  # holding
			self._holding()
		elif evt == 4:  # release
			self._release()
		elif evt == 5 and self._cb_timeout != None:  # timeout
			self._cb_timeout()

	def _click(self):  # switch focus
		if self.comp_num > 0:
			if self.focusIndex == -1:
				self.focusIndex = 0
			else:
				self.componets[self.focusIndex].focus = 0  # lose focus
				self.focusIndex = (self.focusIndex + 1) % self.comp_num
			self.componets[self.focusIndex].focus = 1  # get focus
		if self._cb_click != None:
			self._cb_click()

	def _hold(self):
		if self.comp_num > 0 and self.focusIndex != -1:
			cb = self.componets[self.focusIndex].cb_hold
			if cb != None:
				cb()
		if self._cb_hold != None:
			self._cb_hold()

	def _hold_with_param(self):
		if self.comp_num > 0 and self.focusIndex != -1:
			cb = self.componets[self.focusIndex].cb_hold
			if cb != None:
				self.hold_title = self.componets[
					self.focusIndex].title
				cb()

		if self._cb_hold != None:
			self._cb_hold()

	def _holding(self):
		if self.comp_num > 0 and self.focusIndex != -1:
			cb = self.componets[self.focusIndex].cb_holding
			if cb != None:
				cb()
		if self._cb_holding != None:
			self._cb_holding()

	def _release(self):
		if self.comp_num > 0 and self.focusIndex != -1:
			cb = self.componets[self.focusIndex].cb_release
			if cb != None:
				cb()
		if self._cb_release != None:
			self._cb_release()
